package com.bc.web.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import com.bc.common.CommonEnum.Resp;
import com.bc.common.PayType;
import com.bc.common.message.AccountBalanceChangeReq;
import com.bc.common.message.AccountBalanceChangeResp;
import com.bc.common.message.AccountTransferReq;
import com.bc.common.message.AccountTransferResp;
import com.bc.common.message.BaseResp;
import com.bc.web.config.SystemConfig;
import com.bc.web.model.ClearingDetail;
import com.bc.web.model.ClearingIncome;
import com.bc.web.model.FeeModel;
import com.bc.web.model.Merch;
import com.bc.web.model.Org;
import com.bc.web.model.ShareFee;
import com.fs.common.util.FSHttp;
import com.fs.common.util.FSIDGenerate;
import com.fs.common.util.FSJson;
import com.fs.common.util.FSLog;
import com.fs.common.util.FSMD5;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

/**
 * 机构分润
 * 
 * @author Reed
 * @date 2017年8月24日
 */
public class ClearingIncomeService {
	private static final String CHARGE_URL = SystemConfig.config.get("trade_system_url") + "/income/charge";
	private static final String TRANSFER_URL = SystemConfig.config.get("trade_system_url") + "/income/transfer";
	private static final String ACCOUNTNO = "C00000000000001";

	/**
	 * 渠道收入
	 * 
	 * @param settleDate
	 * @return
	 */
	public BaseResp channelIncome(String settleDate) {
		BaseResp resp = new BaseResp();
		String sql = "select channelCode,sum(fee-channelFee) AS income from clearing_detail where settleDate = ? group by channelCode";
		List<Record> recordList = Db.find(sql, settleDate);
		if (recordList.isEmpty()) {
			FSLog.web.info("无交易数据，无法提取收入");
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "无交易数据，无法提取收入");
		}
		for (Record r : recordList) {
			String channelCode = r.getStr("channelCode");
			ClearingIncome clearingIncome = ClearingIncome.dao.selectChannelIncome(settleDate, channelCode);
			if (clearingIncome != null) {
				FSLog.web.info("渠道收入不能重复提取");
				return resp.setCodeAndMsg(Resp.Fail.getCode(), "渠道收入不能重复提取");
			}
		}
		Merch merch = Merch.dao.selectByMerchCode(ACCOUNTNO);
		Org org = Org.dao.selectByOrgCode(merch.getOrgCode());
		for (Record r : recordList) {
			String channelCode = r.getStr("channelCode");
			Integer income = r.getBigDecimal("income") == null ? 0 : r.getBigDecimal("income").intValue();
			if (income == 0) {
				continue;
			}

			AccountBalanceChangeReq req = new AccountBalanceChangeReq();
			req.setVersion("V1.0");
			req.setChannelNo(channelCode);
			req.setOrgCode(merch.getOrgCode());
			req.setMerchCode(ACCOUNTNO);
			String merchOrderNo = FSIDGenerate.nextShareTradeNo();
			req.setRequestOrderNo(merchOrderNo);
			req.setPayType(PayType.CHARGE);
			req.setAmount(income.toString());
			req.setRemark("提取收入");
			req.setSign(FSMD5.sortSign(req, org.getSafeKey()));

			String rspString;
			AccountBalanceChangeResp rsp;
			try {
				rspString = FSHttp.postJson(CHARGE_URL, FSJson.toString(req));
				rsp = FSJson.toObject(rspString, AccountBalanceChangeResp.class);
			} catch (Exception e) {
				e.printStackTrace();
				FSLog.web.info("提取渠道收入发生异常");
				return resp.setCodeAndMsg(Resp.Fail.getCode(), "提取渠道收入发生异常");
			}
			FSLog.web.info("提取东道收入返回结果 - >" + rspString);
			if (rsp.getRespCode().equals(Resp.Success.getCode())) {
				ClearingIncome c = new ClearingIncome();
				c.setId(FSIDGenerate.getUUID());
				c.setSettleDate(settleDate);
				c.setChannelCode(channelCode);
				c.setBeforeBalance(Long.parseLong(rsp.getBalance()) - income);
				c.setAmount(income);
				c.setType("0"); // 渠道收入
				c.save();
				resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
			} else {
				FSLog.web.info(channelCode + "提取渠道收入失败");
				resp.setCodeAndMsg(Resp.Fail.getCode(), "提取渠道收入发生异常");
			}
		}
		return resp;
	}

	/**
	 * 机构分润
	 * 
	 * @param settleDate
	 * @return
	 */
	public BaseResp orgShare(String settleDate) {
		BaseResp resp = new BaseResp();
		ClearingIncome clearingIncome = ClearingIncome.dao.selectOrgShare(settleDate);
		// 当天已分润，不能重复操作
		if (clearingIncome != null) {
			FSLog.web.info("日切日期：" + settleDate + "已分润，不能重复操作。");
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "日切日期：" + settleDate + "已分润，不能重复操作。");
		}

		// 取出所有非差价机构分润费率
		List<ShareFee> fixedList = ShareFee.dao.selectIsFixed();
		// 取出所有差价机构分润费率
		List<ShareFee> notFixedList = ShareFee.dao.selectIsNotFixed();
		if (fixedList.isEmpty() && notFixedList.isEmpty()) {
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "无分润费率");
		}
		List<ShareFee> feeList = new ArrayList<>(fixedList.size() + notFixedList.size());
		feeList.addAll(fixedList);
		feeList.addAll(notFixedList);
		for (int i = 0; i < feeList.size(); i++) {
			ShareFee fee = feeList.get(i);
			List<ClearingDetail> shareOrderList = ClearingDetail.dao.selectShareOrder(settleDate, fee.getChannelCode(),
					fee.getMerchCode(), fee.getPayTypeCode());
			if (shareOrderList.isEmpty()) {
				continue;
			}
			int payTypeProfit = 0;
			for (int j = 0; j < shareOrderList.size(); j++) {
				ClearingDetail clearingDetail = shareOrderList.get(j);
				payTypeProfit = payTypeProfit + calcProfit(fee, clearingDetail);
			}
			// 保存支付类别分润记录
			if (payTypeProfit > 0) {
				resp = saveShareOrder(settleDate, fee.getChannelCode(), fee.getOrgCode(), fee.getPayTypeCode(),
						payTypeProfit);
			}
		}
		return resp;
	}

	/**
	 * 保存分润订单
	 * 
	 * @param orgCode
	 * @param payType
	 * @param payTypeProfit
	 * @return
	 */
	private BaseResp saveShareOrder(String settleDate, String channelCode, String orgCode, String payType,
			Integer payTypeProfit) {
		BaseResp resp = new BaseResp();
		ClearingIncome clearingIncome = ClearingIncome.dao.selectOrgShare(settleDate, channelCode, orgCode, payType);
		AccountTransferReq req = new AccountTransferReq();
		req.setVersion("V1.0");
		req.setOrgCode(orgCode);
		req.setMerchCode(ACCOUNTNO);
		req.setPayType(PayType.TRANS_OUT);
		String requestOrderNo = FSIDGenerate.nextShareTradeNo();
		req.setRequestOrderNo(requestOrderNo);
		req.setChannelNo(channelCode);
		req.setFromAccountNo(ACCOUNTNO);
		req.setToAccountNo(orgCode);
		req.setAmount(payTypeProfit.toString());
		req.setRemark("机构分润");
		Org org = Org.dao.selectByOrgCode(orgCode);
		req.setSign(FSMD5.sortSign(req, org.getSafeKey()));

		String rspString;
		AccountTransferResp rsp;
		try {
			rspString = FSHttp.postJson(TRANSFER_URL, FSJson.toString(req));
			rsp = FSJson.toObject(rspString, AccountTransferResp.class);
		} catch (Exception e) {
			e.printStackTrace();
			FSLog.web.error(e);
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "机构分润异常");
		}
		FSLog.web.info("分润结果 - >" + rspString);
		if (Resp.Success.getCode().equals(rsp.getRespCode())) {
			if (clearingIncome == null) {
				ClearingIncome c = new ClearingIncome();
				c.setId(requestOrderNo);
				c.setSettleDate(settleDate);
				c.setChannelCode(channelCode);
				c.setOrgCode(orgCode);
				c.setPayTypeCode(payType);
				c.setBeforeBalance(Long.parseLong(rsp.getToAccountBalance()) - payTypeProfit);
				c.setAmount(payTypeProfit);
				c.setType("1");// 机构分润
				c.save();
			} else {
				clearingIncome.setAmount(clearingIncome.getAmount() + payTypeProfit);
				clearingIncome.setBeforeBalance(Long.parseLong(rsp.getToAccountBalance()) - payTypeProfit);
				clearingIncome.update();
			}
			resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
		} else {
			FSLog.web.info(orgCode + "分润失败");
			resp.setCodeAndMsg(Resp.Fail.getCode(), "分润失败");
		}
		return resp;
	}

	/**
	 * 计算分润金额
	 * 
	 * @param fee
	 * @param clearingDetail
	 * @return
	 */
	private Integer calcProfit(ShareFee fee, ClearingDetail clearingDetail) {
		Boolean isFixed = fee.getIsFixed();
		Integer shareAmount = 0;
		if (!isFixed) {
			Integer orgFee = fee(clearingDetail.getAmount(), fee.getShareFeeId());
			if (orgFee == null) {
				orgFee = 0;
			}
			// 第一级机构机构的分润=商户手续费-机构成本手续费
			shareAmount = clearingDetail.getFee() - orgFee;
		} else {
			shareAmount = fee(clearingDetail.getAmount(), fee.getShareFeeId());
		}
		if (shareAmount == null) {
			shareAmount = 0;
		}
		return shareAmount;
	}

	/**
	 * 获取手续费
	 * 
	 * @param amount
	 * @param feeId
	 * @return
	 */
	public Integer fee(Integer amount, Integer feeId) {
		FeeModel f = FeeModel.dao.findById(feeId);
		String rate = f.getRate();
		int maxFee = f.getMaxFee() == null ? 0 : f.getMaxFee();
		int minFee = f.getMinFee() == null ? 0 : f.getMinFee();
		return calcResult(amount, rate, maxFee, minFee);
	}

	/**
	 * 计算
	 * 
	 * @param amount
	 * @param rate
	 * @param maxFee
	 * @param minFee
	 * @return
	 */
	private Integer calcResult(Integer amount, String rate, Integer maxFee, Integer minFee) {
		Integer minfee = minFee; // 最低
		Integer maxfee = maxFee; // 封顶

		BigDecimal bAmount = new BigDecimal(amount);
		BigDecimal bRate = new BigDecimal(rate);
		// 0.6%，数据库中费率的值是0.6，计算时要除以100
		BigDecimal b100 = new BigDecimal(100);
		BigDecimal temp = bAmount.multiply(bRate).divide(b100).setScale(2, BigDecimal.ROUND_HALF_DOWN);
		int fee = temp.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
		// [最低]手续费
		if (minfee != null && minfee > 0 && fee < minfee) {
			fee = minfee;
		}
		// [封顶]手续费
		if (maxfee != null && maxfee > 0 && fee > maxfee) {
			fee = maxfee;
		}
		// 最低、封顶值设置有误
		if (minfee != null && maxfee != null && maxfee > 0 && minfee > maxfee) {
			return null;
		}
		return fee;
	}

}
